#include <cstdint>
#include <systemc.h>

template <uint32_t N, uint32_t M = 1 << N> // N 是输入信号的位数, 输出信号的数量 M = 2^N
SC_MODULE(Decoder) {
    // [端口定义]
    sc_in<bool>         enable; // 使能输入
    sc_in<sc_uint<N>>   input;  // 使用 sc_uint<N> 作为 N 位输入信号
    sc_out<sc_uint<M>>  output; // 使用 sc_uint<M> 作为 M 位输出信号

    // [译码逻辑]
    void decode_logic() {
        // 如果使能信号为低电平，则所有输出信号都为低电平
        if (!enable) {
            output.write(0);
        } 
        // 否则对输入信号进行译码
        else {
            assert(input.read() < M); // 确保输入信号在有效范围内
            output.write(1 << input.read()); // 输出信号为 2^input
        } 
    }

    // [构造函数]
    SC_CTOR(Decoder) {
        SC_METHOD(decode_logic); // 注册逻辑处理函数
        sensitive << input << enable; // 敏感列表
    }
}; // 模板模块定义结束

// 显示为二进制字符串
uint8_t to_binary(sc_uint<4> value) {
    return value.to_uint();
}

int sc_main(int argc, char* argv[]) {
    const uint32_t IN_WIDTH = 2; // 输入信号的位数
    const uint32_t OUT_WIDTH = 1 << IN_WIDTH; // 输出信号的位数

    // [实例化模块]
    Decoder<2> decoder("decoder_2_to_4"); 

    // [声明信号]
    sc_signal<bool> enable;
    sc_signal<sc_uint<IN_WIDTH>> input;
    sc_signal<sc_uint<OUT_WIDTH>> output;

    // [绑定端口]
    decoder.enable(enable);
    decoder.input(input);
    decoder.output(output);

    // [波形追踪]
    sc_trace_file *tf = sc_create_vcd_trace_file("decoder");
    tf->set_time_unit(1, SC_NS); // 设置时间单位为 1 ns
    sc_trace(tf, enable, "enable");
    sc_trace(tf, input, "input");
    sc_trace(tf, output, "output");

    // [施加激励]
    printf("e i o | @time\n");
    printf("------|------\n");
    enable.write(false); // 使能信号为低电平
    for (uint32_t i = 0; i < OUT_WIDTH; i++) {
        input.write(i); // 输入信号为 i
        sc_start(10, SC_NS); // 时间步进 10 ns
        printf("%d %d %d | %s\n", enable.read(), input.read().to_uint(), output.read().to_uint(), sc_time_stamp().to_string().c_str());
    }
    enable.write(true); // 使能信号为高电平
    for (uint32_t i = 0; i < OUT_WIDTH; i++) {
        input.write(i); // 输入信号为 i
        sc_start(10, SC_NS); // 时间步进 10 ns
        printf("%d %d %d | %s\n", enable.read(), input.read().to_uint(), output.read().to_uint(), sc_time_stamp().to_string().c_str());
    }

    // [关闭波形文件]
    sc_close_vcd_trace_file(tf);

    return 0;
}
